/*:
* @plugindesc (v1.02)遇敵控制
* @author 小c
* @version 1.0.0
* @date 3/30/2020
*
* @help
* 地圖遇敵控制。
*
* 1. 追加遇敵-除編輯器遇敵外的額外遇敵
* 地圖示籤
* 例子1：
* <Encounter Item>
* troopId: 5, 6
* region: 1, 2, 3
* weight: 5
* <Encounter Condition>
* //JavaScript code
* if($gameSwitches.value(5))
*     condition = true;
* else
*     condition = false;
* </Encounter Condition>
* </Encounter Item>
*
* 內容說明如下
* troopId：必需，指定敵群編號，可配單項或多項，多項以半角逗號分隔
* region：可選，指定遇敵區域，可多於3個，省略時範圍為全圖
* weight：必需，遇敵權重，如果troopId為多項，此項可為多項
* Encounter Condition：可選，遇敵額外條件，condition為true會遇敵
* 此標籤的各屬性必須按照上述順序書寫
* troopId為多項時weight的補充說明：
* 1. weight的項數可為單項，每個敵群權重都是該值。
* 2. weight的項數可與troopId項數相等，此時每個敵群與權重一一對應
*
* 舉個例子：
* 例子2
* <Encounter Item>
* troopId: 7, 8, 10
* weight: 5, 6, 7
* <Encounter Condition>
* if($gameParty.gold() > 10000)
*     condition = true;
* else
*     condition = false;
* </Encounter Condition>
* </Encounter Item>
* 在例子1當中，5、6敵群權重都是5
* 在例子2當中，7號敵群權重5，8號敵群權重6，10號敵群權重7
*
* 2. 遇敵頻率
* 地圖示籤
* <Encounter Step: x>設定遇敵步數為x
* <Encounter Step: Variable x>設定遇敵步數為變量x
* <Encounter Step: +Variable x>增加遇敵步數為變量x
* <Encounter Step: -Variable x>減少遇敵步數為變量x
* <Encounter Step Eval>
* //JavaScript code
* step = $gameParty.gold() / 100;
* </Encounter Step Eval>
* 動態指定遇敵步數step，若出現錯誤，將返回編輯器的數值
*
* 這幾個標籤的執行順序為：編輯器-標籤賦值-變量賦值-變量加-變量減-JS運
* 算-返回遇敵步數
*
* 插件指令
* ResetEncounterCount 重置遇敵步數
* 遇敵頻率手動改變【比如改變指定變量數值後】建議調用
*
* 更新說明
* v1.00
* 插件完成
*
* v1.01
* 補充靜態對象的CP前綴
* 將所有的eval寫法轉換為函數寫法
*
* v1.02
* 修改troopId和weight為多項參數
* 修復配置了條件代碼的敵群在非遇敵區域內遇到的問題
*/

var Imported = Imported || {};
Imported.CP_EncounterCore = true;

var CP = CP || {};
CP.EncounterManager = CP.EncounterManager || {};

CP.EncounterManager.MAP_LOADED = DataManager.isMapLoaded;
DataManager.isMapLoaded = function() {
	if(!CP.EncounterManager.MAP_LOADED.call(this))
		return false;

	CP.EncounterManager.loadCounterItem();
	CP.EncounterManager.loadCounterStep();

	return true;
};

CP.EncounterManager.loadCounterItem = function(){
	var reg = /<Encounter Item>\s+troopId:\s*([\s\S]+?)\s+(region:\s*([\s\S]+?)\s+)?weight:\s*([\s\S]+?)\s+(<Encounter Condition>([\s\S]*?)<\/Encounter Condition>)?\s*?<\/Encounter Item>/g;
	var data = null;

	while(data = reg.exec($dataMap.note)){
		var troopIdStr = data[1].split(",");
		var troopIds = [];
		troopIdStr.forEach(function(idStr){
			var id = Number(idStr) || 0;
			if(id > 0)
				troopIds.push(id);
		});
		if(troopIds.length <= 0)
			continue;

		var regions = [];
		if(data[3]){
			var regionStrs = data[3].split(",");
			regionStrs.forEach(function(region){
				var s = Number(region) || 0;
				if(s > 0)
					regions.push(s);
			});
		}

		var weights = [];
		if(data[4]){
			var weightStr = data[4].split(",");
			weightStr.forEach(function(weight){
				var w = Number(weight) || 0;
				if(w <= 0)
					w = 5;
				weights.push(w);
			});
		}

		var weightMuti = weights.length > 1;
		for(var i = 0; i < troopIds.length; i++){
			var item = {};
			item.troopId = troopIds[i];
			item.regionSet = regions;
			item.weight = weightMuti ? weights[i] : weights[0];
			item.condition = null;

			if(data[6])
				item.condition = new Function("condition", data[6].trim() + "\nreturn condition;");

			$dataMap.encounterList.push(item);
		}
	}
};

CP.EncounterManager.loadCounterStep = function(){
	$dataMap.encounterStepData = {};
	this.loadCounterStepData();
	this.loadCounterStepEval();
};

CP.EncounterManager.loadCounterStepData = function(){
	var reg1 = /<Encounter Step:\s*([\s\S]*?)>/g;
	var data1 = null;
	var data2 = null;

	while(data1 = reg1.exec($dataMap.note)){
		var reg2 = /^(\d+)/;
		var reg3 = /(\+|-)?Variable (\d+)/;
		var str = data1[1].trim();

		if(reg2.exec(str))
			$dataMap.encounterStepData["Step"] = Number(RegExp.$1) || 0;
		
		if(data2 = reg3.exec(str)){
			if(!data2[1])
				$dataMap.encounterStepData["Variable Step"] = Number(data2[2]);
			else if(data2[1] == "+")
				$dataMap.encounterStepData["Variable Plus"] = Number(data2[2]);
			else
				$dataMap.encounterStepData["Variable Sub"] = Number(data2[2]);
		}
	}
};

CP.EncounterManager.loadCounterStepEval = function(){
	var reg = /<Encounter Step Eval>([\S\s]*)<\/Encounter Step Eval>/;
	if(reg.exec($dataMap.note))
		$dataMap.encounterStepData["Eval"] = new Function("step", RegExp.$1.trim() + "\nreturn step;");
};

//---------------------------------------
//         Game_Player
//---------------------------------------
CP.EncounterManager.MEETS_ENCOUNTER_CONDITIONS = Game_Player.prototype.meetsEncounterConditions;
Game_Player.prototype.meetsEncounterConditions = function(encounter) {
	var condition = CP.EncounterManager.MEETS_ENCOUNTER_CONDITIONS.call(this, encounter);
	
	try{
		if(!condition)
			return false;
		else if(encounter.condition)
			return encounter.condition.call(this, condition);
		else
			return true;
	}catch(err){
		console.error(err);
		return false;
	}
};

//---------------------------------------
//         Game_Map
//---------------------------------------
Game_Map.prototype.processEncounterStepChangeByVariable = function(step, variableId, isPlus){
	var value = $gameVariables.value(variableId);
	
	if(isPlus)
		step += value;
	else
		step -= value;

	return step > 0 ? step : 0;
};

Game_Map.prototype.processEncounterStepEval = function(step){
	var func = $dataMap.encounterStepData["Eval"];
	var base = step;

	try{
		return Math.ceil(func.call(this, step));
	}catch(err){
		console.error(err);
		return base;
	};
};

CP.EncounterManager.ENCOUNTER_STEP = Game_Map.prototype.encounterStep;
Game_Map.prototype.encounterStep = function(){
    var step = CP.EncounterManager.ENCOUNTER_STEP.call(this);
    var base = step;

    if($dataMap.encounterStepData["Step"])
    	step = $dataMap.encounterStepData["Step"];
    if($dataMap.encounterStepData["Variable Step"])
    	step = $gameVariables.value($dataMap.encounterStepData["Variable Step"]);
    if($dataMap.encounterStepData["Variable Plus"])
    	step = this.processEncounterStepChangeByVariable(step, $dataMap.encounterStepData["Variable Plus"], true);
    if($dataMap.encounterStepData["Variable Sub"])
    	step = this.processEncounterStepChangeByVariable(step, $dataMap.encounterStepData["Variable Sub"], false);
    if($dataMap.encounterStepData["Eval"])
    	step = this.processEncounterStepEval(step);

    return step > 0 ? step : base;
};

//---------------------------------------
//         Game_Interpreter
//---------------------------------------
CP.EncounterManager.PLGIN_COMMAND = Game_Interpreter.prototype.pluginCommand;
Game_Interpreter.prototype.pluginCommand = function(command, args){
	CP.EncounterManager.PLGIN_COMMAND.call(this, command, args);

	if(command == 'ResetEncounterCount'){
		$gamePlayer.makeEncounterCount();
	}
};